package framework.mvc.servlet;

import framework.mvc.annotation.Action;
import framework.mvc.annotation.Controller;
import framework.mvc.annotation.Result;
import framework.mvc.enu.ResultType;
import framework.mvc.util.JsonUtil;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;

import java.io.File;
import java.io.FilenameFilter;
import java.io.IOException;
import java.io.PrintWriter;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;

public class ActionServlet extends HttpServlet {

    public static final String BASEPACKAGE="basePackage";
    public static final String ENCODINGG="encoding";

    private String basePackage;

    private String encoding;

    private Map<String,Handler> handlers=new HashMap<>();


    private class Handler{
        private Object obj;
        private Method method;
        private Action action;

        public Handler() {
        }

        public Handler(Object obj, Method method, Action action) {
            this.obj = obj;
            this.method = method;
            this.action = action;
        }

        @Override
        public String toString() {
            return "Handler{" +
                    "obj=" + obj +
                    ", method=" + method +
                    ", action=" + action +
                    '}';
        }

        public Object getObj() {
            return obj;
        }

        public void setObj(Object obj) {
            this.obj = obj;
        }

        public Method getMethod() {
            return method;
        }

        public void setMethod(Method method) {
            this.method = method;
        }

        public Action getAction() {
            return action;
        }

        public void setAction(Action action) {
            this.action = action;
        }
    }


    @Override
    public void init() throws ServletException {

        try {
            basePackage=getInitParameter(BASEPACKAGE);

            System.out.println("basePackage = " + basePackage);

            encoding=getInitParameter(ENCODINGG);

            String realPath=ActionServlet.class
                    .getClassLoader()
                    .getResource(basePackage.replace(".","/"))
                    .getPath();

            System.out.println("realPath = " + realPath);

            //找到所有Action字节码文件所在的目录
            File dir=new File(realPath);

            //找到所有Action的字节码文件（加了@Controller注解的类）

            File[] files=dir.listFiles(new FilenameFilter() {
                @Override
                public boolean accept(File dir, String name) {
                    return name.endsWith(".class")&&!name.contains("$");
                }
            });

            for (File file : files) {
                String simpleClassName=file.getName().substring(0,file.getName().lastIndexOf(".class"));
                
                String actionClassName=basePackage+"."+simpleClassName;

                Class actionClass=Class.forName(actionClassName);

                Controller controller= (Controller) actionClass.getAnnotation(Controller.class);

                //有Controller注解的类是Action
                if(controller!=null){


                    //创建Action对象
                    Object actionObject=actionClass.newInstance();

                    //获得Action类上的Action配置信息path
                    Action classAction= (Action) actionClass.getAnnotation(Action.class);

                    String actionPath="";
                    if(classAction!=null){
                        actionPath=classAction.path();
                    }

                    //获得Action类中所有非private的方法
                    Method[] methods=actionClass.getMethods();

                    for (Method method : methods) {
                        Action methodAction=method.getAnnotation(Action.class);

                        //排除没有Action注解的方法
                        if(methodAction==null){
                            continue;
                        }

                        //真正请求路径
                        String methodPath=methodAction.path();
                        //Action对象 处理方法对象  配置信息
                        Handler handler=new Handler(actionObject,method,methodAction);

                        //缓存
                        handlers.put(actionPath+methodPath,handler);
                    }







                }

            }




        } catch (Exception e) {
            e.printStackTrace();
            throw new ServletException(e);
        }

        handlers.entrySet().forEach(System.out::println);
    }

    @Override
    protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        System.out.println("ActionServlet.service()");

        try{

            request.setCharacterEncoding(encoding);




            //解析请求
            String path=request.getServletPath();
            path=path.substring(0,path.lastIndexOf("."));
            System.out.println("path = " + path);

            //根据path查找配置的handler
            Handler handler=handlers.get(path);
            System.out.println("handler = " + handler);

            //当请求不存在对应的handler时
            if(handler==null){
                response.sendError(HttpServletResponse.SC_NOT_FOUND,path+"不存在");
                return;
            }


            Object actionObject=handler.getObj();
            Method handlerMethod=handler.getMethod();
            Action methodAction=handler.getAction();


            //直接转发到jsp页面
            if(!"".equals(methodAction.forward())){
                System.out.println("forward = " + methodAction);
                request.getRequestDispatcher(methodAction.forward()).forward(request,response);
                return;
            }

            //调用处理者方法
            Object handlerResult=handlerMethod.invoke(actionObject,request,response);

            System.out.println("handlerResult = " + handlerResult);

            //如果Action中方法返回是null
            if(handlerResult==null){
                return;
            }

            //json处理
            if(!(handlerResult instanceof String)){

                Result[] results=methodAction.results();

                if(results.length==0){
                    response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR,"result类型未配置");
                    return;
                }

                Result result=results[0];

                if(!ResultType.JSON.equals(result.type())){
                    response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR,"result类型不是json");
                    return;
                }

                response.setContentType("application/json;charset="+encoding);

                PrintWriter out=response.getWriter();

                String json= JsonUtil.toJson(handlerResult);

                out.print(json);

                out.flush();

                return;

            }


            //如果Action中方法返回值后面有?传参
            String param="";
            if(((String)handlerResult).indexOf("?")!=-1){
                String[] s=((String)handlerResult).split("\\?");
                handlerResult=s[0];
                param="?"+s[1];
            }




            //将Result数组转换成Map
            Result[] results=methodAction.results();
            Map<String,Result> resultMap= Arrays.stream(results)
                    .collect(Collectors.toMap(Result::name, Function.identity()));

            //根据处理者方法返回的结果查找Result配置
//            Result actionResult= Arrays.stream(results)
//                                       .filter(result -> handlerResult.equals(result.name()))
//                                       .findAny()
//                                       .get();
            Result actionResult=resultMap.get(handlerResult);

            System.out.println("actionResult = " + actionResult);

            //如果处理者返回的字符串在配置中不存在
            if(actionResult==null){
                response.sendError(HttpServletResponse.SC_NOT_FOUND,handlerResult+"不存在");
                return;
            }
            
            //根据Result中的type和path生成对应的响应
            if(ResultType.REDIRECT.equals(actionResult.type())){
                //重定向
                response.sendRedirect(request.getContextPath()+actionResult.path()+param);
                return;
            }

            if(ResultType.FORWARD.equals(actionResult.type())){
                //转发
                request.getRequestDispatcher(actionResult.path()).forward(request,response);
                return;
            }







        }catch (Exception e){
            e.printStackTrace();
            throw new ServletException(e);
        }

    }
}
